package com.asen.commons.core.meta.entity;

import com.asen.commons.annotation.EntityModel;
import com.asen.commons.core.base.domain.Core;
import com.asen.commons.core.meta.loader.EntityObjectLoader;
import com.asen.commons.core.utils.EntityUtils;
import com.asen.commons.utils.BaseAssert;
import com.asen.commons.utils.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 实体表
 *
 * @author ls
 * @version 1.0
 * @date 2024-04-09
 */
public class EntityObject {

    /**
     * 实体类
     */
    private Class<?> entityClass;

    /**
     * 包名
     */
    private String pkgName;

    /**
     * 实体名
     */
    private String name;

    /**
     * 别名
     */
    private String alias;

    /**
     * 表名
     */
    private String table;

    /**
     * 描述
     */
    private String desc;

    /**
     * 主键
     */
    private List<String> keyProperties;
    private List<String> keyColumns;

    private List<FieldObject> fieldList = new ArrayList<>();

    public EntityObject() {
    }

    public EntityObject(Class<?> entityClass) {
        this.entityClass = entityClass;
        if (entityClass != null) {
            this.pkgName = entityClass.getPackage().getName();
            this.name = entityClass.getSimpleName();
        }
        this.alias = this.name;
    }

    public void setEntityTable(EntityModel entityTable) {
        if (StringUtils.isNotEmpty(entityTable.name())) {
            this.name = entityTable.name();
        }

        if (StringUtils.isNotEmpty(entityTable.value())) {
            this.alias = entityTable.value();
        }

        if (StringUtils.isNotEmpty(entityTable.table())) {
            this.table = entityTable.table();
        }

        if (StringUtils.isNotEmpty(entityTable.desc())) {
            this.desc = entityTable.desc();
        }
    }

    public FieldObject getFieldObject(String name) {
        FieldObject fieldObject = null;
        for (FieldObject fo : fieldList) {
            if (fo.getName().equals(name)) {
                fieldObject = fo;
                break;
            }
        }
        return fieldObject;
    }

    /**
     * 根据filedName取值
     *
     * @param fullName
     * @return
     */
    public Object getFieldValue(Object model, String fullName) throws Exception {
        if (model == null) {
            return null;
        }

        int index = fullName.indexOf(".");
        if (index <= 0) {
            FieldObject fo = getFieldObject(fullName);
            if (fo == null) {
                return null;
            }
            return fo.getValue(model);
        }

        String fieldName = fullName.substring(0, index);
        String subName = fullName.substring(index + 1);
        FieldObject fo = getFieldObject(fieldName);
        Object subModel = fo.getValue(model);
        EntityObject eo = EntityObjectLoader.getInstance().get(fo.getJavaType());
        return eo.getFieldValue(subModel, subName);
    }

    public void setFieldValue(Object model, String fullName, Object value) throws Exception {
        if (model == null) {
            return;
        }

        int index = fullName.indexOf(".");
        if (index <= 0) {
            setSimpleValue(model, fullName, value);
            return;
        }

        String fieldName = fullName.substring(0, index);
        String subName = fullName.substring(index + 1, fullName.length());
        FieldObject fo = getFieldObject(fieldName);

        Object subModel = fo.getValue(model);
        if (subModel == null) {
            subModel = fo.getJavaType().newInstance();
            setFieldValue(model, fieldName, subModel);
        }

        EntityObject eo = EntityObjectLoader.getInstance().get(fo.getJavaType());
        eo.setFieldValue(subModel, subName, value);
    }

    public void setSimpleValue(Object model, String fieldName, Object value) throws Exception {
        if (model == null || value == null) {
            return;
        }

        FieldObject fo = getFieldObject(fieldName);
        if (fo == null) {
            return;
        }

        // 简单属性
        if (EntityUtils.isSimpleType(fo.getJavaType())) {
            if (fo.getJavaType().isAssignableFrom(value.getClass())) {
                fo.setValue(model, value);
            } else if (Boolean.class.isAssignableFrom(fo.getJavaType())) {
                if ("true".equalsIgnoreCase(value.toString()) || "1".equals(value.toString())) {
                    fo.setValue(model, Boolean.TRUE);
                } else {
                    fo.setValue(model, Boolean.FALSE);
                }
            } else if (value instanceof Boolean) {
                if (Integer.class.isAssignableFrom(fo.getJavaType())) {
                    fo.setValue(model, Boolean.TRUE.equals(value) ? 1 : 0);
                }
            }
            return;
        }

        // 关联对象属性
        Object fieldModel = fo.getValue(model);
        if (fieldModel == null) {
            fieldModel = fo.getJavaType().newInstance();
            fo.setValue(model, fieldModel);
        }

        BaseAssert.check(value instanceof Long, "不合法的ID类型【" + value.getClass().getName() + "】");

        Long id = (Long) value;

        if (Core.class.isAssignableFrom(fo.getJavaType())) {
            ((Core) fieldModel).setId(id);
            return;
        }

        EntityObject eo = EntityObjectLoader.getInstance().load(fo.getJavaType());
        BaseAssert.check(eo.hasField("id"), "不支持没有ID属性的类型【" + fo.getJavaType().getName() + "】");

        eo.setFieldValue(fieldModel, "id", id);
    }

    public boolean hasField(String fieldName) {
        for (FieldObject fo : fieldList) {
            if (fo.getName().equals(fieldName)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 全部存在
     */
    public boolean hasAllFields(String... fieldNames) {
        if (fieldNames.length == 0) {
            return false;
        }
        int findCount = 0;
        List<String> list = Arrays.asList(fieldNames);
        for (FieldObject fo : fieldList) {
            if (list.contains(fo.getName())) {
                findCount++;
            }
        }
        return list.size() == findCount;
    }

    /**
     * 存在任意一个
     */
    public boolean hasAnyFields(String... fieldNames) {
        if (fieldNames.length == 0) {
            return false;
        }
        List<String> list = Arrays.asList(fieldNames);
        for (FieldObject fo : fieldList) {
            if (list.contains(fo.getName())) {
                return true;
            }
        }
        return false;
    }

    public void addFieldObject(FieldObject fieldObject) {
        fieldList.add(fieldObject);
    }

    public Class<?> getEntityClass() {
        return entityClass;
    }

    public void setEntityClass(Class<?> entityClass) {
        this.entityClass = entityClass;
    }

    public String getPkgName() {
        return pkgName;
    }

    public void setPkgName(String pkgName) {
        this.pkgName = pkgName;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAlias() {
        return alias;
    }

    public void setAlias(String alias) {
        this.alias = alias;
    }

    public String getTable() {
        if (StringUtils.isEmpty(this.table)) {
            String packageName = entityClass.getPackage().getName();
            String[] sections = packageName.split("\\.");
            String moduleName = sections[sections.length - 2];
            this.table = moduleName + "_" + EntityUtils.camelhumpToUnderline(entityClass.getSimpleName());
        }

        return table;
    }

    public String getTableInner() {
        return table;
    }

    public void setTable(String table) {
        this.table = table;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public List<String> getKeyProperties() {
        return keyProperties;
    }

    public void setKeyProperties(List<String> keyProperties) {
        this.keyProperties = keyProperties;
    }

    public List<String> getKeyColumns() {
        return keyColumns;
    }

    public void setKeyColumns(List<String> keyColumns) {
        this.keyColumns = keyColumns;
    }

    public List<FieldObject> getFieldList() {
        return fieldList;
    }

    public void setFieldList(List<FieldObject> fieldList) {
        this.fieldList = fieldList;
    }

    public List<FieldObject> getSubEntryList() {
        return fieldList.stream().filter(FieldObject::isSubEntry).collect(Collectors.toList());
    }
}
